//*************************************************************************************************
//************************ (C) 2001 - 2006, Eleven Engineering Incorporated ***********************
//*************************************************************************************************
//**
//**		Tabs:	This file looks best with tab stops set every 6 spaces.
//**
//*************************************************************************************************
//*************************************************************************************************
//**
//**          File:  XPD Serial.asm
//**       Project:  XInc2 Library
//**       Created:  04 Jan 2003 by Ryan Northcott
//**       Revised:  08 Sep 2006 by Dan Beutel
//**
//**   Description:  Firmware subroutines to configure, read data, and write data using the XInc2
//**                 Program / Debug Port.  To use these routines in your project, you must assign
//**                 kSPI0CS_Semaphore to one of your hardware semaphores.
//**
//** Compatibility:  Requires XInA v4.4 or higher.
//**
//**    Disclaimer:  You may incorporate this sample source code into your program(s) without
//**                 restriction.  This sample source code has been provided "AS IS" and the
//**                 responsibility for its operation is yours.  You are not permitted to
//**                 redistribute this sample source code as "Eleven sample source code" after
//**                 having made changes.  If you are going to re-distribute the source, we require
//**                 that you make it clear in the source that the code was descended from Eleven
//**                 sample source code, but that you have made changes.
//**
//*************************************************************************************************
//*************************************************************************************************
//**
//** High Level Routines:
//**
//**	XPD_Configure
//**	XPD_ReadConfigWord
//**
//**	XPD_WriteByte
//**	XPD_ReadByte
//**	XPD_ReadByteWithTimeout
//**	XPD_ReadWriteByte
//**
//** Low Level Routines:
//**
//**	XPD_ShiftInOut
//**
//*************************************************************************************************
//*************************************************************************************************


#ifndef __XPD_SERIAL__
#define __XPD_SERIAL__

//=============================================================================
// Input Params:	r1 = Configuration Word (Sum of Configuration Constants)
// Output Params:	r1 = Configuration Succeeded (true or false)
//-----------------------------------------------------------------------------
// Description:	Used to configure the XPD Port.
//
//			This routine always sets up SPI0 for polarity=0, phase=0, and
//			mode=master.
//
//			The default settings are:
//				Baud Rate:		230.4k
//				Data Bits:		8
//				Parity Bits:	None
//				Stop Bits:		1
//				Timing:		Standard
//				Running:		True
//				FIFO:			Enabled
//				Clock:		3MHz or less
//
//			To change these settings, add the desired constants
//			to the Configuration Word.
//
//			At 3.3V the maximum SPI0 clock supported by the MAX3100
//			SPI-UART is 1.5MHz.  Therefore, to get the fastest possible
//			data rate on the SPI, you should add the first XInc2 Clock
//			Speed Constant that is faster than the actual speed of the
//			XInc2 clock to your Configuration Word.
//=============================================================================
XPD_Configure:
		st	r6, sp, 0
		st	r1, sp, 1
		add	sp, sp, 2

	// Setup the SEM Address Mux
	// GPB[0:3] = SPI as output
	//	GPB0 		= SPI ROM CS
	//	GPB[1:2]	= SPI MUX Address decoding 
	//		0b001 = SPI XPD Port
		mov	r1, 0x0707
		outp	r1, GPBcfg

	// Derive a config word for the SPI0 Port from the XPD Config Word
		ld	r1, sp, -1
		rol	r1, r1, -6				// Move the "Clock Speed Constant" into its appropriate position
		and	r1, r1, 0b0000000001011100
		bis	r1, r1, 1				// Set the "Master SPI" bit
		bic	r1, r1, 6				// Test the "Shutdown" bit
		bc	VS, XPD_Configure_Disable
		bis	r1, r1, 0				// Set the "Enable SPI" bit
		
	XPD_Configure_Disable:
		outp	r1, SPI0cfg

	// Test if the UART hardware exists by configuring it with a non-zero dummy baudrate
		mov	r1, 0xC00F				// "Write Config" command in upper two bits
		jsr	r6, XPD_ShiftInOut		// Write the configuration word
		
		mov	r1, 0x4000				// "Read Config" command in upper two bits
		jsr	r6, XPD_ShiftInOut		// Read the configuration word
		
		sub	r1, r1, 0x400F			// Check for correct baud rate
		bc	EQ, XPD_Configure_UART_Attached
		mov	r1, false				// Return false
		bra	XPD_Configure_END

	XPD_Configure_UART_Attached:
		ld	r1, sp, -1
		and	r1, r1, 0b1111100011111111
		ior	r1, r1, 0xC000			// "Write Config" command in upper two bits
		jsr	r6, XPD_ShiftInOut		// Write config, also clears receive FIFO
	
		mov	r1, true				// Return true
		
XPD_Configure_END:
		sub	sp, sp, 2
		// Don't restore r1
		ld	r6, sp, 0
		
		jsr	r6, r6



//=============================================================================
// Input Params:  None
// Output Params: r1 = Configuration Word
//-----------------------------------------------------------------------------
// Description:	Reads config and status data from the SPI-UART.  Can be used
//			to determine the status of the transmit and receive buffers
//			by checking the transmit and receive bits.
//=============================================================================
XPD_ReadConfigWord:
		st	r6, sp, 0
		add	sp, sp, 1

		mov	r1, 0x4000				// "Read Config" command in upper two bits
		jsr	r6, XPD_ShiftInOut		// Read the configuration word

		sub	sp, sp, 1
		ld	r6, sp, 0

		jsr	r6, r6



//=============================================================================
// Input Params:	r1 = The byte to write
// Output Params:	None
//-----------------------------------------------------------------------------
// Description:	Used to shift a data byte out to the SPI-UART.  The data byte
//			shifted in is discarded.  The data is always in the LSB of
//			the word.
//=============================================================================
XPD_WriteByte:
		st	r6, sp, 0
		st	r1, sp, 1					// Push r1 because XPD_ReadConfigWord uses it
		add	sp, sp, 2

	XPD_WriteByte_LOOP:
		jsr	r6, XPD_ReadConfigWord
		bic	r1, r1, kXPD_TransmitDoneBit		// Is transmit buffer empty?
		bc	VC, XPD_WriteByte_LOOP
		ld	r1, sp, -1					// Reload r1 from the stack
		and	r1, r1, 0x07FF
		bis	r1, r1, 15
		jsr	r6, XPD_ShiftInOut

		sub	sp, sp, 2
		ld	r6, sp, 0
		ld	r1, sp, 1

		jsr	r6, r6



//=============================================================================
// Input Params:	None
// Output Params:	r1 = The byte read from the SPI-UART
//-----------------------------------------------------------------------------
// Description:	Used to shift a data byte in from the SPI-UART.  A zero byte
//			is shifted out.  This subroutine does not return until a byte
//			has been received.  The data is always in the LSB of the
//			word.
//=============================================================================
XPD_ReadByte:
		st	r6, sp, 0
		add	sp, sp, 1

	XPD_ReadByte_LOOP:
		mov	r1, 0
		jsr	r6, XPD_ShiftInOut
		bis	r1, r1, kXPD_DataReceivedBit	// Has byte arrived?
		bc	VC, XPD_ReadByte_LOOP
		and	r1, r1, 0x07FF

		sub	sp, sp, 1
		ld	r6, sp, 0

		jsr	r6, r6



//=============================================================================
// Input Params:	r1 = The maximum number of read attempts
// Output Params:	r1 = The byte read from the SPI-UART
//-----------------------------------------------------------------------------
// Description:	Used to read a data byte from the SPI-UART.  A zero byte is
//			shifted out.  This subroutine does not return until a byte
//			has been received or the maximum number of attempts has been
//			reached.  The data is always in the LSB of the word.
//=============================================================================
XPD_ReadByteWithTimeout:
		st	r2, sp, 0
		st	r6, sp, 1
		add	sp, sp, 2

		add	r2, r1, 0				// r2 = counter
	XPD_ReadByteWithTimeout_LOOP:
		bc	ZS, XPD_ReadByteWithTimeout_FAIL
		mov	r1, 0
		jsr	r6, XPD_ShiftInOut
		bis	r1, r1, kXPD_DataReceivedBit	// Has byte arrived?
		bc	VS, XPD_ReadByteWithTimeout_SUCCESS
		sub	r2, r2, 1
		bra	XPD_ReadByteWithTimeout_LOOP

	XPD_ReadByteWithTimeout_SUCCESS:
		and	r1, r1, 0x07FF
		bra	XPD_ReadByteWithTimeout_END

	XPD_ReadByteWithTimeout_FAIL:
		mov	r1, 0xFFFF

	XPD_ReadByteWithTimeout_END:
		sub	sp, sp, 2
		ld	r2, sp, 0
		ld	r6, sp, 1

		jsr	r6, r6



//=============================================================================
// Input Params:	r1 = The byte to write
// Output Params:	r1 = The byte read back
//-----------------------------------------------------------------------------
// Description:	Used to shift out a data byte to the SPI-UART and to shift
//			back in another byte from the SPI-UART.  The data is always
//			in the LSB of the word.
//=============================================================================
XPD_ReadWriteByte:
		st	r6, sp, 0
		st	r1, sp, 1					// Push r1 because XPD_ReadConfigWord uses it
		add	sp, sp, 2

	XPD_ReadWriteByte_LOOP:
		jsr	r6, XPD_ReadConfigWord
		bic	r1, r1, kXPD_TransmitDoneBit		// Is transmit buffer empty?
		bc	VC, XPD_ReadWriteByte_LOOP
		sub	sp, sp, 1					// Pop r1
		ld	r1, sp, 0
		and	r1, r1,0x07FF
		bis	r1, r1, 15
		jsr	r6, XPD_ShiftInOut

		sub	sp, sp, 1
		ld	r6, sp, 0

		jsr	r6, r6



//=============================================================================
// Input Params:	r1 = 16-bit word to write to the SPI-UART
// Output Params:	r1 = 16-bit word read back from the SPI-UART
//-----------------------------------------------------------------------------
// Description:	Used to shift out the word in r1 to the SPI-UART and to
//			read back a word into r1.  The MSB of the word is a control
//			byte and the LSB is a data byte.
//=============================================================================
XPD_ShiftInOut:
		st	r0, sp, 0
		st	r2, sp, 1

		mov	r2, kSPI0CS_Semaphore
		outp	r2, SCUdown			// Resource down (semaphore)

		inp	r0, GPBin
		bic	r0, r0, 1
		bic	r0, r0, 2
		outp	r0, GPBout			// Assert SPI-UART chip select

		rol	r0, r1, 8			// Move MSbyte to r0
		outp	r0, SPI0tx			// Output MSbyte
		inp	r0, SPI0rx			// Get received MSbyte
		outp	r1, SPI0tx			// Output LSbyte
		rol	r1, r0, 8			// Move MSbyte received into data register
		inp	r0, SPI0rx			// Get received LSbyte
		ior	r1, r1, r0			// Move received LSbyte to data register

		inp	r0, GPBin
		bis	r0, r0, 1
		bis	r0, r0, 2
		outp	r0, GPBout			// Negate SPI-UART chip select

		outp	r2, SCUup			// Resource up (semaphore)

		ld	r0, sp, 0
		ld	r2, sp, 1

		jsr	r6, r6

#endif